package com.easyim.imclient.client;

import com.easyim.common.message.Immessage;
import com.easyim.imclient.config.ClientProperties;
import com.easyim.imclient.handler.ImClientHandler;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.protobuf.ProtobufDecoder;
import io.netty.handler.codec.protobuf.ProtobufEncoder;
import io.netty.handler.codec.protobuf.ProtobufVarint32FrameDecoder;
import io.netty.handler.codec.protobuf.ProtobufVarint32LengthFieldPrepender;
import lombok.Data;

/**
 *  这个客户端 是一个线程对应一个客户端。做承载力测试将来可以用，其实可以做一些比如用五个线程模拟客户端。然后可以模拟多个客户端 发完再建立那种，那种也行 但是不符合实际 搞一个线程池 去建立连接 然后操作后释放连接
 *  当然可以 但是我们选择用一个线程一个线程跑这个 到时候搞多台机器压力测试 才是最贴近真实的数据
 */

@Data
public class SingleThreadClient implements Runnable{

    ClientProperties clientProperties;

    Integer index;

    @Override
    public void run() {
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        Integer receiverIndex = index+1;
        try {
            Bootstrap bootstrap = new Bootstrap();
            bootstrap.group(workerGroup)
                    .channel(NioSocketChannel.class)
                    .option(ChannelOption.SO_KEEPALIVE, true)
                    .handler(new ChannelInitializer<Channel>() {
                        @Override
                        protected void initChannel(Channel ch) throws Exception {
                            ch.pipeline().addLast(new ProtobufVarint32FrameDecoder());
                            ch.pipeline().addLast(new ProtobufDecoder(
                                    Immessage.ImMessage.getDefaultInstance()));
                            ch.pipeline().addLast(new ProtobufVarint32LengthFieldPrepender());
                            ch.pipeline().addLast(new ProtobufEncoder());
                            ch.pipeline().addLast(new ImClientHandler());
                        }
                    });

            ChannelFuture channelFuture = bootstrap.connect(clientProperties.getServerHost(), clientProperties.getServerPort()).sync();
            Channel channel = channelFuture.channel();
            String username = clientProperties.getUsernamePrefix() + index;
            String receiver = clientProperties.getUsernamePrefix() + receiverIndex;
            //鉴权
            auth(username, channel);
            //发消息
            Thread.sleep(2000);
            sendMsg(username, receiver, channel);
            channel.closeFuture().sync();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            workerGroup.shutdownGracefully();
        }
    }


    //先建立连接


    //客户端鉴权 鉴权成功才可以发 否则服务器会断开连接
    private void auth(String username, Channel channel){
        // 构建 Protocol Buffers 消息
        Immessage.ImMessage.Builder messageBuilder =Immessage.ImMessage.newBuilder();
        Immessage.CmdMessage.Builder authBuild = Immessage.CmdMessage.newBuilder();
        authBuild.setCommand(Immessage.CmdMessage.CommandType.CONNECT);
        authBuild.setDevice("windows");
        authBuild.setUsername(username);
        authBuild.setToken(clientProperties.getToken());
        Immessage.CmdMessage authInfo = authBuild.build();
        Immessage.ImMessage authMsg = messageBuilder.setCmdMessage(authInfo).build();
        //验证
        channel.writeAndFlush(authMsg);
    }


    private void sendMsg(String username, String receiver,Channel channel){
        // 构建 Protocol Buffers 消息
        Immessage.ImMessage.Builder messageBuilder2 =Immessage.ImMessage.newBuilder();
        Immessage.DataMessage.Builder msgBuild = Immessage.DataMessage.newBuilder();
        msgBuild.setSender(username);
        msgBuild.setReceiver(receiver);
        msgBuild.setChatType(Immessage.ChatType.CHAT);
        for (int i = 0; i < clientProperties.getSendCount(); i++) {
            msgBuild.setContent(clientProperties.getMsgContext()+i);
            Immessage.DataMessage msgContent = msgBuild.build();
            Immessage.ImMessage msg = messageBuilder2.setDataMessage(msgContent).build();
            //发送消息内容
            channel.writeAndFlush(msg);
        }
    }





}
